Skip to content

Simplify and clean up Win32 Cursor implementation#3220

Open
HeikoKlare wants to merge 2 commits intoeclipse-platform:masterfrom
HeikoKlare:cleanup/cursor-win32-simplifications
Open

Simplify and clean up Win32 Cursor implementation#3220
HeikoKlare wants to merge 2 commits intoeclipse-platform:masterfrom
HeikoKlare:cleanup/cursor-win32-simplifications

Conversation

@HeikoKlare
Copy link
Copy Markdown
Contributor

@HeikoKlare HeikoKlare commented Apr 10, 2026

Summary

This pull request simplifies and cleans up the Win32-specific Cursor class (bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java) and adds a corresponding set of Win32-specific unit tests.

Note: These changes were developed with the assistance of GitHub Copilot.


Code Simplifications & Improvements

Change Reason
Replace double map-lookup + setHandleForZoomLevel() with HashMap.computeIfAbsent() in win32_getHandle() The helper method contained redundant null/containsKey guards; both are collapsed into a single idiomatic call
Change win32_getHandle() return type from boxed Long to primitive long Consistent with Font.win32_getHandle(), Image.win32_getHandle(), and Region.win32_getHandle(); eliminates unnecessary boxing overhead; all call sites already used long
Fix latent equality bug in equals(): Long wrapper objects compared with == Cursor handles are OS memory addresses far outside the JVM integer cache range [-128, 127], so == on Long could silently return false for equal handles. With the primitive return type, == on long is now correct
Use Java 16 instanceof pattern matching in equals() Eliminates the redundant explicit cast after the type check
Remove unnecessary clone() in ImageDataWithMaskCursorHandleProvider.validateMask() The cloned ImageData was only ever read for its width/height fields — the defensive copy was pure overhead
Remove redundant static modifier on the nested CursorHandleProvider interface Nested interfaces are implicitly static in Java
Remove redundant final modifier on private static method getOSCursorIdFromStyle() private static methods cannot be overridden; final is meaningless here
Remove redundant final modifier on lambda-captured local variable in destroyHandlesExcept() The variable is already effectively final without the explicit keyword

New Win32-Specific Tests

A new test class CursorWin32Tests was added alongside the existing Win32 test classes, following the same patterns used in RegionWin32Tests and ImagesWin32Tests.

Test What it covers
testDisposedCursorReturnsZeroHandle Verifies the isDisposed() guard at the top of win32_getHandle() returns 0L after disposal
testHandleIsCachedForSameZoomLevel Verifies the computeIfAbsent() caching — repeated calls with the same zoom return the identical cached OS handle
testImageDataCursorProducesDifferentHandlesForDifferentZoomLevels Verifies that ImageDataCursorHandleProvider scales the source image and produces a distinct OS cursor handle per zoom level
testDestroyHandlesExceptPreservesRetainedHandle Verifies that destroyHandlesExcept() leaves the retained zoom entry intact without marking the cursor as disposed

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 10, 2026

Test Results (win32)

   30 files  +2     30 suites  +2   4m 33s ⏱️ -3s
4 657 tests +4  4 584 ✅ +4  73 💤 ±0  0 ❌ ±0 
1 191 runs  +4  1 167 ✅ +4  24 💤 ±0  0 ❌ ±0 

Results for commit 68ef2f3. ± Comparison against base commit 16e501f.

♻️ This comment has been updated with latest results.

@vogella
Copy link
Copy Markdown
Contributor

vogella commented Apr 10, 2026

The new tests look like they are not so helpful, I would not not test win32_getHandle in isolation.

@HeikoKlare
Copy link
Copy Markdown
Contributor Author

The new tests look like they are not so helpful, I would not not test win32_getHandle in isolation.

Why do you think so? Those are actual unit tests (which SWT is mostly lacking). Some of them may not be that useful, but having core functionality of per-zoom handle provision, non-redundancy etc. regression tested sounds reasonable to me to make SWT develop less "let's hope we don't break anything, but we have sufficient time to find implicitly find regressions until the release" 🙂

@vogella
Copy link
Copy Markdown
Contributor

vogella commented Apr 10, 2026

The only useful tests seem to be the last two once to me (starting with void testImageDataCursorProducesDifferentHandlesForDifferentZoomLevels).

But if the "a cursor creates a handler" tests are useful to you, that is fine for me. Just keep an open eye for AI slope, no need to pollute our repos with unnecessary tests.

HeikoKlare and others added 2 commits April 10, 2026 16:56
Several small improvements to the Win32 Cursor implementation:

- Replace double map-lookup and setHandleForZoomLevel() helper with a
  single HashMap.computeIfAbsent() call in win32_getHandle(). The
  helper method contained redundant null/containsKey guards that were
  already enforced by the call-site; both are now unnecessary.

- Change win32_getHandle() return type from boxed Long to primitive
  long, consistent with Font.win32_getHandle(), Image.win32_getHandle()
  and Region.win32_getHandle(). All existing call sites already
  consumed the result as a long, so no callers required changes.

- Fix latent equality bug in equals(): the previous code compared two
  Long wrapper objects with ==, which only gives correct results for
  cached values in [-128, 127]. Cursor handles are OS memory addresses
  and fall well outside that range. With the primitive return type the
  comparison is now a straightforward == on long values, which is both
  correct and avoids boxing.

- Use Java 16+ instanceof pattern matching in equals() to eliminate
  the explicit cast after the type check.

- Remove unnecessary clone() in ImageDataWithMaskCursorHandleProvider
  .validateMask(): the cloned ImageData was only ever read for its
  width/height fields, so the defensive copy was pure overhead.

- Remove redundant 'static' modifier on the nested CursorHandleProvider
  interface declaration; nested interfaces are implicitly static.

- Remove redundant 'final' modifier on the private static method
  getOSCursorIdFromStyle(); private static methods cannot be overridden.

- Remove redundant 'final' modifier on the lambda-captured local
  variable in destroyHandlesExcept(); the variable is effectively final
  without the explicit keyword.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CursorWin32Tests covers behaviour that is either Windows-only or
directly exercises the internal implementation paths changed in the
preceding cleanup commit:

- testDisposedCursorReturnsZeroHandle: verifies the isDisposed() guard
  at the top of win32_getHandle() returns 0L after disposal.

- testHandleIsCachedForSameZoomLevel: verifies the computeIfAbsent()
  caching - two calls with the same zoom must return the identical
  cached OS handle without re-creating it.

- testImageDataCursorProducesDifferentHandlesForDifferentZoomLevels:
  verifies that ImageDataCursorHandleProvider scales the source image
  and produces a distinct OS cursor handle for each zoom level.

- testDestroyHandlesExceptPreservesRetainedHandle: verifies that
  destroyHandlesExcept() leaves the retained zoom entry intact and
  does not mark the cursor as disposed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@HeikoKlare HeikoKlare force-pushed the cleanup/cursor-win32-simplifications branch from fc2497e to 68ef2f3 Compare April 10, 2026 14:59
@HeikoKlare
Copy link
Copy Markdown
Contributor Author

But if the "a cursor creates a handler" tests are useful to you, that is fine for me. Just keep an open eye for AI slope, no need to pollute our repos with unnecessary tests.

Sure, we must not accept whatever an agent proposed, so I have an eye on slop. As said, I agree that some tests are rather useless, which is why I removed them. I just kept those tests that ensure important contracts of the Win32 cursor implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants